﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using Dataglot;
using IrishSettings.TableControllers;

namespace IrishSettings
{
    //public class SchemaInfo
    //{
    //    public string Application { get; set; }
    //    public Version Version { get; set; }
    //    public long SchemaItems { get; set; }
    //    public bool SchemaIsStored{ get; set; }
    //}


    /// <summary>
    /// This class will do all complex transactions regarding the schema table and is used in initializing settings before use.
    /// </summary>
    /// <remarks>
    /// This class works closely with the DbApplicationManager class, which creates the parent object for a schema.
    /// </remarks>
    public class DbSchemaManager: ConnectionConsumer, IDisposable
    {
        public SettingsApplication CurrentApplication;

        public DbSchemaManager(DataFactory factory)
            : base(factory)
        {
        }

        public DbSchemaManager(SettingsApplication application, DataFactory factory)
            : base(factory)
        {
            if (application == null)
                throw new ArgumentException("A valid application object required upon construction.");
            CurrentApplication = application;
        }

        public DbSchemaManager(SettingsApplication application, DataFactory sharedFactory, DbConnection sharedConnection, TransactionManager sharedTransactionManager)
            : base(sharedFactory, sharedConnection, sharedTransactionManager)
        {
            if (application == null)
                throw new ArgumentException("A valid application object required upon construction.");
            if(sharedFactory==null)
                throw new ArgumentNullException("sharedFactory","Data factory is null");
            if (sharedConnection == null)
                throw new ArgumentNullException("sharedConnection", "sharedConnection is null");

            CurrentApplication = application;
        }

        public bool SchemaIsStored(SettingsApplication applicationInQuestion, Version target)
        {
            if (target == null)
                throw new ArgumentNullException("target", "Version can't be null");
            if (string.IsNullOrEmpty(applicationInQuestion.Application))
                throw new InvalidOperationException("current application name required");

            bool doesApplicationExist;
            OpenConnection();
            using (ApplicationAndVersionController aavc = new ApplicationAndVersionController(factory,con,null))
            {
                doesApplicationExist = aavc.ExistsByApplicationName(applicationInQuestion.Application, target);
            }
            
            if (doesApplicationExist == false) 
                return false;

            return CountSchemaItems(applicationInQuestion,target) > 0;
        }

        private int CountSchemaItems(SettingsApplication applicationInQuestion, Version target)
        {
            if (applicationInQuestion.Id == 0) return 0;

            OpenConnection();

            using(SchemaSettingsController controller = new SchemaSettingsController(factory,con, null))
            {
                return controller.SelectListOfIdsByVersion(applicationInQuestion.Id, target).Count;
            }
        }

        /// <summary>
        /// Using a settings schema defined in code, insert it.
        /// </summary>
        /// <param name="schema"></param>
        public SettingsSchema InsertSchema(SettingsSchema schema)
        {
            if(schema.Count==0)
            {
                throw new InvalidOperationException("schema parameter has zero items, either something is wrong or this method doesn't need to be executed.");
            }

            OpenConnection();
            BeginTransaction();
            using(ApplicationAndVersionController appController = new ApplicationAndVersionController(factory,con,Transaction))
            {
                SettingsApplicationStored result;
                if (CurrentApplication.Id == 0)
                {
                    if (
                        !appController.ExistsByApplicationName(CurrentApplication.Application,
                                                                CurrentApplication.VersionObject))
                    {
                        //local schema object should just have an SettingsApplication property.
                        SettingsApplication appStored = new SettingsApplication();
                        appStored.Application = CurrentApplication.Application;
                        appStored.Version = CurrentApplication.VersionObject.ToString();
                        appStored.Culture = CurrentApplication.CultureObject.ToString();
                        appStored.IsActiveVersion = true;
                        result = appController.Insert(appStored);
                    }
                    else
                    {
                        result = appController.SelectByApplicationName(CurrentApplication.Application,
                                                                        CurrentApplication.VersionObject);
                    }
                    CurrentApplication.Id = result.Id;
                }

                using (SchemaSettingsController schemaSettingsController = new SchemaSettingsController(factory,con, Transaction))
                {
                    foreach (GenericSettingSchema schemaRow in schema.Values)
                    {
                        if (schemaRow.Id == 0)
                        {
                            GenericSettingSchema schemaItem;
                            schemaRow.ApplicationId = CurrentApplication.Id;
                            if (!schemaSettingsController.ExistByName(schemaRow.Name, CurrentApplication.Id))
                            {
                                schemaItem = schemaSettingsController.Insert(schemaRow);
                            }
                            else
                            {
                                schemaItem = schemaSettingsController.SelectByName(schemaRow.Name, CurrentApplication.Id);
                            }
                            schemaRow.Id = schemaItem.Id;
                        }
                    }
                }
            }
            CommitIfRequired();
            
            return schema;
        }



        public SettingsSchema LoadSchemaForCurrentEnvironment(Version versionObject)
        {
            //Anything by machine name, domain?
            //Anything by checking the appSettings?
            //Is there just one application there?

            SettingsSchema result;
            OpenConnection();
            BeginTransaction();

            SchemaSettingsController controller = new SchemaSettingsController(factory,con, Transaction);
            {
                result = controller.SelectListByVersion(CurrentApplication.Application, versionObject);
                result.Validate();
            }
            CommitIfRequired();
            foreach (var item in result.Values)
            {
                if (item.Id == 0)
                {
                    throw new InvalidOperationException("This schema doesn't have Id's");
                }
            }
            return result;
        }
    }
}